package cn.king.springframework.context.event;

import cn.king.springframework.beans.BeanException;
import cn.king.springframework.beans.factory.BeanFactory;
import cn.king.springframework.beans.factory.BeanFactoryAware;
import cn.king.springframework.context.ApplicationEvent;
import cn.king.springframework.context.ApplicationListener;
import cn.king.springframework.util.ClassUtil;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {

    public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new HashSet<>();
    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeanException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
    }

    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.remove(listener);

    }

    /**
     * 返回匹配给定的applicationlistener的集合
     * *事件类型。不匹配的侦听器会被尽早排除。
     * * @param event要传播的事件。允许排除
     * *早期不匹配监听器，基于缓存的匹配信息。
     * *返回applicationlistener的集合
     * @param event
     * @return
     */
    protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event){
        LinkedList<ApplicationListener> allListeners = new LinkedList<>();
        for(ApplicationListener<ApplicationEvent> listener:applicationListeners){
            if(supportsEvent(listener,event)){
                allListeners.add(listener);
            }
        }
        return allListeners;
    }

    /**
     *监听器是否对该事件感兴趣
     */
    protected boolean supportsEvent(ApplicationListener<ApplicationEvent> listener,ApplicationEvent event){
        Class<? extends ApplicationListener> listenerClass = listener.getClass();
        // 按照 CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy 不同的实例化类型，需要判断后获取目标 class
        Class<?> targetClass = ClassUtil.isCglibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass;
        /**
         * 返回类似cn.king.springframework.context.ApplicationListener<cn.king.springframework.context.ApplicationEvent,cn.xxxx.xxxx>
         *的一个数组，但因为本例中只实现了一个接口，所以获取第一个元素即可
         */
        Type genericInterface = targetClass.getGenericInterfaces()[0];
        /**
         * 获取<x,y>里面的每个参数的实际类型
         */
        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String typeName = actualTypeArgument.getTypeName();
        Class<?> eventClass = null;
        try {
            eventClass =  Class.forName(typeName);
        } catch (ClassNotFoundException e) {
            throw new BeanException("wrong event class name: " + typeName);
        }
        // 判定此 eventClass 对象所表示的类或接口与指定的 event.getClass() 参数所表示的类或接口是否相同，或是否是其超类或超接口。
        // isAssignableFrom是用来判断子类和父类的关系的，或者接口的实现类和接口的关系的，默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)结果是true，
        // 证明B可以转换成为A,也就是A可以由B转换而来。
        return eventClass.isAssignableFrom(event.getClass());

    }
}
